package core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.Class;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.trolltech.qt.core.QFileInfo;

/**
 * This class overrides some of the QFileInfo logic, and adds needed logic for
 * our main program (DC) Convince. The classes QFileInfo and
 * QFileInfoCompareable are same in essence, expect how two files compares to
 * each other. This class expends the way they do this operation, and allows the
 * user of the program the methods of doing so.
 * 
 * 
 * 
 * 
 * 
 * @version 1.00 30 Mar 2010
 * @author Aviv Avitan
 */


 class QFileInfoCompare extends QFileInfo {

	private int numOfTotalTests;
	/*
	 * we associate this variable with the options the user chooses to decide if
	 * two files are equal or not.
	 */
	private HashMap<String, Method> allChecksMap = new HashMap<String, Method>();
	private HashMap<String, Object[]> allChecksMapParameters = new HashMap<String, Object[]>();

	// If files are found to be different, the next checks are skipped.
	private boolean fastCheck = false;

	// Lists all of the checks that indicated the files are different
	private List<String> errorsLastRun = new ArrayList<String>();

	public QFileInfoCompare(QFileInfo f) throws SecurityException,
			NoSuchMethodException {

		super(f); // parent copy-constructor

		// Adding default file-equation check
		Class<QFileInfoCompare> c = QFileInfoCompare.class;
		Class<?> parameterTypes[] = new Class<?>[0];
		Method nameCompare = c.getMethod("size", parameterTypes);

		allChecksMap.put("Size", nameCompare);

	}

	public void addTest(Method m, String method_name, Object[] parameterTypes) {
		allChecksMap.put(method_name, m);

		this.allChecksMapParameters.put(method_name, parameterTypes);

		numOfTotalTests++;
	}

	private void addError(String error) {
		this.errorsLastRun.add(error);
	}

	private void clearLastErrors() {
		errorsLastRun.clear();
	}

	public String[] getErrors() {
		return this.errorsLastRun.toArray(new String[0]); // new String[0] is
															// only indication
															// for the array
															// type.
	}

	public boolean equals(Object o) {
		QFileInfo targetFileInfo = (QFileInfo) o;

		boolean isCheckResultEqual = true;
		boolean areFilesEqual = true;
		clearLastErrors();

		for (Map.Entry<String, Method> entry : this.allChecksMap.entrySet()) {
			try {
				Method check = entry.getValue();

				Object[] paras = this.allChecksMapParameters
						.get(entry.getKey());
				Object resultTarget = check.invoke(targetFileInfo, paras);
				Object resultSelf = check.invoke(this, paras);

				isCheckResultEqual = (resultTarget.equals(resultSelf));
				areFilesEqual = areFilesEqual && isCheckResultEqual;

				if (!isCheckResultEqual) {
					this.addError(entry.getKey());
					if (this.fastCheck == true) {
						return false;
					}
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
				return false;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				return false;
			} catch (InvocationTargetException e) {
				e.printStackTrace();
				return false;
			}

		}

		return areFilesEqual;

	}
}
